package myJs.user.workflowMission

import myJs.Utils._

import scala.scalajs.js.Dynamic.{global => g}
import myJs.myPkg._
import myJs.tool.Pojo.FilterContentData
import myJs.tool.Tool
import myJs.tool.Tool._
import myJs.user.mission.MissionManage
import myJs.user.workflow.WorkflowTool
import org.scalajs.dom.ext.Ajax
import org.scalajs.dom.{Event, _}
import scalatags.Text.all._
import scalatags.Text.{TypedTag, all}

import scala.collection.SeqMap
import org.scalajs.macrotaskexecutor.MacrotaskExecutor.Implicits._
import scala.scalajs.js
import scala.scalajs.js.JSConverters._
import scala.scalajs.js.{Date, JSON}
import scala.scalajs.js.annotation.{JSExport, JSExportTopLevel}
import myJs.myPkg.jquery._
import myJs.Implicits._
import myJs.myPkg.bootstrap.Bootstrap.default._
import upickle.default._

/** Created by yz on 2019/4/25
  */
@JSExportTopLevel("WorkflowMissionManage")
object WorkflowMissionManage extends WorkflowTool {
  val formId = "form"
  val tableId = "table"
  val updateFormId = "updateForm"
  val updateModalId = "updateModal"

  @JSExport("init")
  def init = {

    initFilterContent()
    refreshSelect2
    initTable
    refreshTable()
    updateMissionSocket
    registerEvent
    updateFormBootStrapValidator

  }

  override def registerEvent = {
    tableFilterEvent
    $(document.body).on(
      "click",
      s".myEditShow",
      "",
      (y: Element) => {
        val id = $(y).dataId

        editShow(id)
      }
    )
    $(document.body).on(
      "click",
      s".myUpdateName",
      "",
      (y: Element) => {
        updateName
      }
    )
    $(document.body).on(
      "click",
      s".idsButton",
      "",
      (y: Element) => {
        deletes()
      }
    )
    $(document.body).on(
      "click",
      s".myViewLog",
      "",
      (y: Element) => {
        val id = $(y).dataId
        viewLog(id)
      }
    )
    $(document.body).on(
      "click",
      s".myDelete",
      "",
      (y: Element) => {
        val id = $(y).dataId
        delete(id)
      }
    )
  }

  def deletes(parentId: String = "") = {
    val ids = Tool.getIdsValue(parentId)
    val options = SwalOptions(
      title = "",
      text = messages("confirmToDeleteTheTask"),
      `type` = "warning",
      showCancelButton = true,
      showConfirmButton = true,
      confirmButtonClass = Tool.confirmButtonClass,
      confirmButtonText = messages("confirm"),
      closeOnConfirm = false,
      cancelButtonText = messages("cancel"),
      showLoaderOnConfirm = true,
      cancelButtonClass = Tool.cancelButtonClass
    )
    Swal.swal(
      options,
      () => {
        val data = js.Dictionary(
          "ids" -> ids.toJSArray
        )
        val url = g.jsRoutes.controllers.WorkflowController.deletes().url.toString
        Ajax
          .delete(
            url = s"${url}",
            data = JSON.stringify(data),
            headers = Map("Content-Type" -> "application/json"),
            responseType = "blob"
          )
          .map { xhr =>
            refreshTable { () =>
              val options = SwalOptions(
                `type` = "success",
                title = messages("success"),
                text = s"${messages("deleteSuccessfully")}！"
              )
              Swal.swal(options)
              Tool.getIds(parentId)
            }
          }
      }
    )
  }

  def updateName = {
    val formId = updateFormId
    val modalId = updateModalId
    val bv = $(s"#${formId}").bv
    bv.validate()
    val valid = bv.isValid()
    if (valid) {
      val data = $(s"#${formId}").serialize()
      val index = layer.alert(Tool.myElement, Tool.layerOptions)
      val url = g.jsRoutes.controllers.WorkflowController.updateName().url.toString
      Ajax
        .post(url = s"${url}", data = data, headers = Map("Content-Type" -> "application/x-www-form-urlencoded"))
        .map { xhr =>
          refreshTable { () =>
            layer.close(index)
            $(s"#${modalId}").modal("hide")
            bv.resetForm(true)
            val options = SwalOptions(
              `type` = "success",
              title = messages("success"),
              text = messages("modifyTaskNameSuccessfully")
            )
            Swal.swal(options)
          }
        }
    }
  }

  def editShow(id: String) = {
    val url = g.jsRoutes.controllers.WorkflowController.getMissionById().url.toString
    Ajax.get(url = s"${url.noCache}&missionId=${id}").map { xhr =>
      val dict = JSON.parse(xhr.responseText).toJDJAn.toMyJDS
      $("#updateForm input[name='orignalMissionName']").`val`(dict("missionName"))
      $("#updateForm input[name='missionId']").`val`(dict("id"))
      $("#updateModal").modal("show")
    }
  }

  def refreshSelect2 = {
    refreshState
    refreshKind

  }

  def refreshKind = {
    val inputName = "kind"
    val data = Tool.workflows.map(_.nameStr)
    val array = (data).map { v =>
      js.Dictionary("text" -> getShowName(v), "id" -> v)
    }
    val options = Select2Options(data = array.toJSArray, multiple = true, placeholder = messages("clickToChoose"))
    Tool.getInputByName(inputName).select2(options)
  }

  def refreshState = {
    val inputName = "state"
    val data = Tool.stateMap.keyList
    val array = (data).map { v =>
      js.Dictionary("text" -> Tool.getStateShowName(v), "id" -> v)
    }
    val options = Select2Options(data = array.toJSArray, multiple = true, placeholder = messages("clickToChoose"))
    Tool.getInputByName(inputName).select2(options)
  }

  def tableFilterEvent = {
    $(document).on(
      "click",
      (y: Element, e: Event) => {
        val trueY = e.target.asInstanceOf[Element]
        val b = $(trueY).hasClass("select2-selection__choice__remove") ||
          $(trueY).hasClass("select2-search__field") ||
          $(trueY).hasClass("filterContent") ||
          $(trueY).parents().hasClass("filterContent")
        if (!b) {
          $(".filterContent")
            .mapElems(y => y)
            .filter { y =>
              $(y).isVisible
            }
            .foreach { y =>
              Tool.filterContentValueRevert($(y))
              $(y).hide()
            }
        }
      }
    )
    $(document.body).on(
      "click",
      ".myOperate",
      "",
      (y: Element) => {
        MissionManage.filterContentShow(y)
      }
    )
    $(document.body).on(
      "click",
      ".mySortLi",
      "",
      (y: Element) => {
        val parentId = ""
        Tool.execSort(
          y,
          parentId,
          () => {
            refreshTable()
          }
        )
      }
    )
    $(document.body).on(
      "click",
      ".myConfirm",
      "",
      (y: Element) => {
        val parentId = ""
        val map = Map(
          "kind" -> kindShowNameMap,
          "state" -> Tool.stateMap
        )
        Tool.confirmFilter(
          y,
          parentId,
          () => {
            refreshTable()
          },
          map
        )
      }
    )
    $(document.body).on(
      "click",
      ".myHide",
      "",
      (y: Element) => {
        val parentId = ""
        Tool.hideFilterContentWithRevert(y)
      }
    )
    $(document.body).on(
      "click",
      ".myRemove",
      "",
      (y: Element) => {
        val parentId = ""
        Tool.removeCondition(
          y,
          parentId,
          () => {
            refreshTable()
          }
        )
      }
    )
    $(document.body).on(
      "click",
      ".myRemoveSort",
      "",
      (y: Element) => {
        val parentId = ""
        Tool.removeSort(
          y,
          parentId,
          () => {
            refreshTable()
          }
        )
      }
    )
    $(document.body).on(
      "click",
      ".myYear",
      "",
      (y: Element) => {
        val parentId = ""
        Tool.hideFilterContent(y)
        val showYearTextJq = $(y).find(".text")
        val showYearText = showYearTextJq.text().trim
        val showYearStr = messages("showYear")
        val hideYearStr = messages("hideYear")
        val newShowYearText = showYearText match {
          case `showYearStr` => hideYearStr
          case `hideYearStr` => showYearStr
        }
        showYearTextJq.text(newShowYearText)
        refreshTable { () => {} }
      }
    )
  }

  def initFilterContent(tabId: String = "") = {
    val textSortDatas = List(
      FilterContentData("missionName", messages("taskName"))
    )
    val select2SortDatas = List(
      FilterContentData("kind", messages("workflow"), List.empty),
      FilterContentData("state", messages("taskState"), List.empty)
    )
    val timeSortDatas = List(
      FilterContentData("startTime", messages("startTime")),
      FilterContentData("endTime", messages("endTime"))
    )
    Tool.initFilterContent(
      textSortDatas = textSortDatas,
      timeSortDatas = timeSortDatas,
      select2SortDatas = select2SortDatas,
      parentId = s"${tabId}",
      showShowYear = true
    )
  }

  def delete(id: String) = {
    val options = SwalOptions(
      title = "",
      text = messages("deleteConfirm"),
      `type` = "warning",
      showCancelButton = true,
      showConfirmButton = true,
      confirmButtonClass = Tool.confirmButtonClass,
      confirmButtonText = messages("confirm"),
      closeOnConfirm = false,
      cancelButtonText = messages("cancel"),
      showLoaderOnConfirm = true,
      cancelButtonClass = Tool.cancelButtonClass
    )
    Swal.swal(
      options,
      () => {
        val url = g.jsRoutes.controllers.WorkflowController.deleteMissionById().url.toString
        Ajax.delete(url = s"${url}?missionId=${id}").map { xhr =>
          refreshTable { () =>
            val options = SwalOptions(
              `type` = "success",
              title = messages("success"),
              text = messages("deleteSuccessfully")
            )
            Swal.swal(options)
          }
        }
      }
    )
  }

  def viewLog(id: String) = {
    val url = g.jsRoutes.controllers.WorkflowController.getLogContent().url.toString
    Ajax.get(url = s"${url.noCache}&missionId=${id}", headers = Map("Content-Type" -> "application/json")).map { xhr =>
      val data = xhr.response
      val options = LayerOptions
        .`type`(1)
        .title(s"<h4>${messages("viewLog")}</h4>")
        .area(js.Array("900px", "600px"))
        .skin("layui-layer-demo")
        .closeBtn(1)
        .anim(2)
        .shadeClose(true)
        .maxmin(true)
        .content(s"<pre style='word-wrap: break-word' class='genome-pre'>${data}</pre>")
      layer.open(options)
    }
  }

  def updateMissionSocket = {
    val url = g.jsRoutes.controllers.WorkflowController.updateMissionSocket().url.toString
    val wsUri = s"ws://${window.location.host}${url}"
    if(window.location.protocol=="http"){
      webSocket(wsUri)
    }else updateByHand
  }

  def webSocket(wsUri: String) = {
    val websocket = new WebSocket(wsUri)
    websocket.onopen = (evt) => websocket.send(JSON.stringify(js.Dictionary("info" -> "start")))
    websocket.onclose = (evt) => println(s"ERROR:${evt.code},${evt.reason},${evt.wasClean}")
    websocket.onmessage = (evt) => {
      refreshTable()
    }
    websocket.onerror = (evt) => {
      updateByHand
      println(s"ERROR:${evt.toString}")
    }
  }

  def updateByHand = {
    js.timers.setInterval(3000) {
      refreshTable()
    }
  }

  def tableF = {
    val url = g.jsRoutes.controllers.WorkflowController.getAllMission().url.toString
    Ajax.get(url = s"${url.noCache}", headers = Map("Content-Type" -> "application/json")).map { xhr =>
      xhr.responseText.toJArJDJAn.map { array =>
        array.map { case (k, v) =>
          val trueV = if (v == null) "" else v.toString
          (k, trueV)
        }.toJSDictionary

      }
    }
  }

  def sortExec(data: JArJDS, queryMap: Map[String, js.Array[String]]) = {
    val sortOp = queryMap.get("sort").map(_.head)
    val sortData = sortOp
      .map { sort =>
        val ascSortData = sort match {
          case _ => data.sortBy(_(sort))
        }
        queryMap("order").head match {
          case "desc" => ascSortData.reverse
          case "asc" => ascSortData
        }
      }
      .getOrElse(data)
    sortData
  }

  def refreshTable(f: () => js.Any = () => ()) = {
    val parentId = ""
    tableF.map { data =>
      val queryMap = Tool.getQueryMap(parentId)
      val sortData = sortExec(data, queryMap)

      def loopFilter(sortData: JArJDS) = {

        val filterColumns = queryMap.removedAll(List("sort", "order")).filter(_._2.map(_.trim).nonEmpty).keyList

        def loop(acc: JArJDS, elems: List[String]): JArJDS = {
          elems match {
            case Nil => acc
            case y :: ys =>
              val searchV = queryMap(y)
              val vs = searchV
              val fieldName = y.split("\\.")(0)
              val name = y.split("\\.")(1)
              val jq = $(s"#${fieldName}Content").findInputByName(name)
              val curFilterData = if (jq.hasClass("myDatepicker")) {
                acc.filter { row =>
                  val dbDate = row(fieldName)
                  if (name == "startTime") {
                    Tool.timeBefore(vs.head, dbDate)
                  } else {
                    Tool.timeAfter(vs.head, dbDate)
                  }
                }
              } else if (jq.hasClass("select2MultiInput")) {
                acc.filter { row =>
                  vs.exists(row(fieldName) == _)
                }
              } else {
                acc.filter { row =>
                  row(fieldName).contains(vs.head)
                }
              }
              loop(curFilterData, ys)
          }
        }

        loop(sortData, filterColumns)
      }

      val filterData = loopFilter(sortData)
      val columns = getColumns
      $(s"#${tableId}")
        .bootstrapTable("refreshOptions", TableOptions.columns(columns.toJSArray))
        .bootstrapTable("load", filterData)
      f()
    }
  }

  def tbFmt(columnName: String): js.Function = { (v: js.Any, row: js.Dictionary[js.Any]) =>
    {
      val showYearStr = messages("showYear")
      val startTimeShowYear = $("#startTimeContent .myYear span.text").text().trim != showYearStr
      val endTimeShowYear = $("#endTimeContent .myYear span.text").text().trim != showYearStr
      columnName match {
        case "missionName" => {
          if (row.myGet("state") == "success") {
            val viewUrl = g.jsRoutes.controllers.WorkflowController.resultDetailBefore().url.toString
            val viewStr = a(
              title := messages("viewDetails"),
              href := s"${viewUrl}?missionId=${row("id")}",
              cursor.pointer,
              v.toString
            )
            val editStr = a(
              title := messages("modify"),
              cursor.pointer,
              `class` := "myEditShow",
              dataId := s"${row("id")}",
              span(em(cls := "fa fa-edit"))
            )
            List(editStr, viewStr).mkString("&nbsp;")
          } else {
            span(v.toString)
          }
        }
        case "kind" => {
          getKindA(v.toString)
        }
        case "state" => {
          val state1 = if (List("success").contains(row("state"))) {
            span(cls := "label label-success", s"${messages("success")} ")
          } else if (List("running").contains(row("state").toString)) {
            span(
              messages("running"),
              img(cls := "runningImage", src := "/assets/images/running2.gif", width := 30, height := 20)
            )
          } else if (List("wait", "preparing").contains(row("state"))) {
            span(
              span(cls := "label label-default", messages("waiting")),
              all.raw("&nbsp;"),
              img(cls := "runningImage", src := "/assets/images/running2.gif", width := 30, height := 20)
            )
          } else {
            span(cls := "label label-danger", messages("error"))
          }
          state1.toString()
        }
        case "startTime" =>
          val date = new Date(v.toString)
          Tool.dateTimeFormat(date, startTimeShowYear)
        case "endTime" =>
          if (v.toString.nonBlank) {
            val date = new Date(v.toString)
            Tool.dateTimeFormat(date, endTimeShowYear)
          } else v
        case _ => v
      }
    }
  }

  def expStyle(columnName: String): js.Function = (v: js.Any, row: js.Dictionary[Any]) =>
    columnName match {
      case _ => v
    }

  lazy val operateColumn = js.Array(
    ColumnOptions.field("operate").title(messages("operations")).formatter(operateFmt).filterControl("clear")
  )

  @JSExport("operateFmt")
  def operateFmt: js.Function = { (v: js.Any, row: js.Dictionary[js.Any]) =>
    val deleteStr = a(
      title := messages("delete"),
      dataId := s"${row("id")}",
      `class` := "myDelete",
      cursor.pointer,
      target := "_blank",
      span(
        em(cls := "fa fa-close")
      )
    )

    val viewStr = a(
      title := messages("log"),
      dataId := s"${row("id")}",
      `class` := "myViewLog",
      cursor.pointer,
      span(em(cls := "fa fa-file-text"))
    )
    val downloadUrl = g.jsRoutes.controllers.WorkflowController.downloadResult().url.toString
    val downloadStr = a(
      title := messages("download"),
      href := s"${downloadUrl}?missionId=${row("id")}",
      cursor.pointer,
      span(em(cls := "fa fa-download"))
    )

    val reRunUrl = g.jsRoutes.controllers.WorkflowController.reRunMissionBefore().url.toString
    val reRunStr = a(
      title := messages("rerunWithModificantion"),
      href := s"${reRunUrl}?missionId=${row("id")}",
      cursor.pointer,
      //        target:="_blank",
      span(em(cls := "fa fa-refresh"))
    )

    val viewUrl = g.jsRoutes.controllers.WorkflowController.viewHtml().url.toString
    val viewHtmlStr = a(
      title := "View html",
      href := s"${viewUrl}?missionId=${row("id")}",
      cursor.pointer,
      target := "_blank",
      span(em(cls := "fa fa-eye"))
    )

    val state1 = if (List("success", "warning").contains(row.myGet("state"))) {
      List(downloadStr)
    } else List[TypedTag[String]]()

    val state2 = if (List("success", "error").contains(row.myGet("state"))) {
      List(viewStr, reRunStr)
    } else List[TypedTag[String]]()

    val rs = state1 ::: state2 ::: List(deleteStr)
    rs.mkString("&nbsp;")

  }

  val checkColumn = ColumnOptions.field("check").checkbox(true)

  def getColumns = {
    val map = SeqMap(
      "missionName" -> messages("taskName"),
      "kind" -> messages("workflow"),
      "state" -> messages("taskState"),
      "startTime" -> messages("startTime"),
      "endTime" -> messages("endTime")
    )
    val columnNames = map.keyList
    js.Array(checkColumn) ++ columnNames
      .map { columnName =>
        val title = map.getOrElse(columnName, columnName)
        val fmt = tbFmt(columnName)
        val style = expStyle(columnName)
        val basicOptions = ColumnOptions.field(columnName).title(title).sortable(true).formatter(fmt).cellStyle(style)
        columnName match {
          case x if List("missionName", "kind", "state", "startTime", "endTime").contains(x) =>
            basicOptions.sortable(false).operateable(true)
          case _ => basicOptions
        }
      }
      .concat(operateColumn)
  }

  def initTable = {
    val columns = getColumns
    val options =
      TableOptions.columns(columns.toJSArray).searchOnButton(false).filterControl(false).locale(Tool.getBTLanguage)
    $(s"#${tableId}").bootstrapTable(options)
    Tool.dateInit
    Tool.bindEvt()
  }

  def getId = {
    g.id.toString.toInt
  }
  def updateFormBootStrapValidator = {
    def dataF: js.Function = (validator: BootstrapValidator) => {
      js.Dictionary(
        "missionName" -> validator.getFieldElements("missionName").myVal,
        "id" -> getId
      )
    }

    val url = g.jsRoutes.controllers.WorkflowController.missionNameCheck().url.toString
    val dict = js.Dictionary(
      "feedbackIcons" -> js.Dictionary(
        "valid" -> "glyphicon glyphicon-ok",
        "invalid" -> "glyphicon glyphicon-remove",
        "validating" -> "glyphicon glyphicon-refresh"
      ),
      "fields" -> js.Dictionary(
        "missionName" -> {
          val info = messages("taskName")
          js.Dictionary(
            "validators" -> js.Dictionary(
              "notEmpty" -> js.Dictionary(
                "message" -> s"${messages("null")}"
              ),
              "remote" -> js.Dictionary(
                "message" -> s"${messages("exist")}",
                "url" -> url,
                "type" -> "POST",
                "delay" -> 1000,
                "data" -> dataF
              )
            )
          )
        }
      )
    )
    g.$("#updateForm").bootstrapValidator(dict)

  }

}
